#!/bin/python

###
###   this program creates fake temporal data
###   that can be used to test ideas in R and
###   rstudio.  But I needed some known 
###   temporal data to make sure I could find
###   it amongst the noise
###
###   Notes and Assumptions:
###   - doing time over half the year (180 calendar days)
###   - start with 1 Jan 2014
###   - one of the keys will have an event every day
###   - one of the keys will have an event every hour
###   - one of the keys will have an event every Friday
###      at a random time
###   -- -- you get the idea
###
###   Key Naming Conventions:
###   n:    number of events, zero-padded
###   d:    day of month, zero-padded number
###   h:    24-hour of day, zero-padded number
###   m:    minute of the hour, zero-padded
###   e:    
###   v:    variance, zero-padded percentage
###   
###   example:
###   n:00000;d:09;dv:00;h:12;hv:00;m:00;mv:00
###
###   n:12345;rep:01d00h00m;var:00d12h05m


###
###      imports go here...
###
from datetime import datetime as DT
import time
import random
import calendar

###
###      constants // variables go here
###
pipeSep  = "|"
commaSep = ','
colonSep = ":"
semiSep  = ";"
startDateTuple = DT(2014, 1, 1, 0, 0, 0)
endDateTuple   = DT(2014, 5,15,23,59,59)
startTime      = int(time.mktime(startDateTuple.timetuple()))
endTime        = int(time.mktime(endDateTuple.timetuple()))

###
###      functions go here...
###

def secsToIso(seconds = 0) :
   return time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(seconds))

def genIPAddrs(numToGen = 20000) :
   myRand = random
   myRand.seed(1)
   listOfIPS = []
   for x in range(0,numToGen):
      ip = ""
      for octect in range(0,4):
         ip += str(myRand.randint(1,254)).zfill(3)
         ip += '.'
      ip = ip.strip('.')
      listOfIPS.append(ip)
   return listOfIPS

def calcSecondsFromKey(key):
   oneSecond   = 1
   oneMinute   = oneSecond * 60
   oneHour     = oneMinute * 60
   oneDay      = oneHour   * 24
   (temp,key) = key.split(':')
   (dySecs,key) = key.split('d')
   (hrSecs,key) = key.split('h')
   (mnSecs,key) = key.split('m')
   seconds = (int(dySecs)*oneDay) + (int(hrSecs)*oneHour) + (int(mnSecs)*oneMinute)
   return int(seconds)

def genTimes(startDateObject, stopDateObject, repKey, varKey):
###
### repKey = rand...
###
   myRand = random
   myRand.seed()
   startSeconds  = int(time.mktime(startDateObject.timetuple()))
   endSeconds    = int(time.mktime(stopDateObject.timetuple()))
   ###   account for timezone offsets from GMT//UTC
   ###   otherwise, daylight savings time messes things up
   startSeconds -= time.timezone
   endSeconds -= time.timezone
   count = 0
   times = []
   if repKey.lower().count('rand'):
      ###
      ###   Deal with the request for random times
      ###   I really want a negatively skew log distribution
      ###   therefore, take the normal log and invert...
      ###
      numPossSecs = endSeconds - startSeconds
      if numPossSecs > 25:
         exponent = len(str(numPossSecs))
         exponent = int(exponent / 2) + 1
         denominator = (10**exponent) / (myRand.lognormvariate(0.0625,1))
         numberOfEvents = (numPossSecs) / (int(denominator))
         times = myRand.sample(xrange(startSeconds,endSeconds),numberOfEvents)
      else:
         numberOfEvents = myRand.randint(1,int((numPossSecs/4)))
         times = myRand.sample(xrange(startSeconds,endSeconds),numberOfEvents)
   else :
      ###
      ###   Must be we want a repeat pattern
      ###
      repeatPatternSeconds = calcSecondsFromKey(repKey)
      variancePatternSeconds = calcSecondsFromKey(varKey)
      variancePatternSeconds = variancePatternSeconds / 2
      for i in range(startSeconds, endSeconds, repeatPatternSeconds):
         i += myRand.randint( -1 * variancePatternSeconds , variancePatternSeconds)
         if ( i < startSeconds ) or ( i > endSeconds ) :
            continue
         count += 1
         times.append(i)
   return times

def genEvents(startDateObject, endDateObject, repKey, varKey, myIPS):
   pipeSep  = "|"
   commaSep = ','
   colonSep = ":"
   semiSep  = ";"
   myRand = random
   myRand.seed(len(myIPS))
   myRand.shuffle(myIPS)
   retval = []
   if repKey.lower().count('rand'):
      repKey = "rep:" + repKey
      varKey = "var:00d00h00m"
   times = genTimes(startDateObject, endDateObject, repKey, varKey)
   count = str(len(times)).zfill(5)
   dataKey = colonSep.join(["n",count])
   start   = colonSep.join(["sta",startDateObject.isoformat()])
   end     = colonSep.join(["end",endDateObject.isoformat()])
   dataKey = semiSep.join([dataKey,start,end,repKey,varKey])
   fromIP = myRand.choice(myIPS)
   toIP = myRand.choice(myIPS)
   while fromIP == toIP:
      toIP = myRand.choice(myIPS)
   ###
   ###   output record format:
   ###   record|AB_Count|ISO_Time|dataKey
   ###   epoch:fromIP:toIP | count | iso8601 | n:times;repKey;varKey
   for t in times:
      record = colonSep.join([str(t),fromIP,toIP])
      isotime = secsToIso(int(t))
      record = pipeSep.join([record,count,isotime,dataKey])
      retval.append(record)
   return retval

###
###      BEGIN MAIN
###
records = []

###   create a pool of ip addresses to use
ips = genIPAddrs()

###
###   create some daily keys and values
###
SDT=DT(2014,1,1,12,0,0,)
EDT=DT(2014,5,15,23,59,59)
repKey = "rep:01d00h00m"
varKey = "var:00d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d00h20m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d06h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d09h45m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:01d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

###
###   Create hourly keys and values
###
SDT=DT(2013,11,11,12,0,0)
EDT=DT(2014,5,15,23,59,59)
repKey = "rep:00d01h00m"
varKey = "var:00d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d00h20m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d00h59m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

###
###   hmmm...  how about a repeat pattern of 42 minutes....
###
repKey = "rep:00d00h42m"
varKey = "var:00d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

varKey = "var:00d00h09m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

###
###   other repeating patterns and variances...
###
repKey = "rep:07d00h00m"
varKey = "var:00d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

repKey = "rep:03d00h00m"
varKey = "var:01d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

repKey = "rep:21d00h00m"
varKey = "var:02d02h02m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

repKey = "rep:00d09h00m"
varKey = "var:00d03h33m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

repKey = "rep:01d01h01m"
varKey = "var:00d00h00m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results

repKey = "rep:02d02h02m"
varKey = "var:00d07h07m"
results = genEvents(SDT,EDT,repKey,varKey,ips)
records += results


###   ###
###   ###   create lots of random events as noise...
###   ###
for i in range(1,100):
   SDT=DT(2013,11,11,12,0,0,)
   EDT=DT(2014,5,15,23,59,59)
   repKey = "random" + str(i).zfill(3)
   results = genEvents(SDT,EDT,repKey,varKey,ips)
   records += results
###
###   Create some random events with random start and end dates
###
for i in range(101,200):
   lrand = random
   lrand.seed(269)
   startMonth = int(lrand.randint(1,4))
   endMonth   = int(lrand.randint(2,5))
   while startMonth >= endMonth:
      endMonth   = int(lrand.randint(2,5))
   lastDayStartMonth = calendar.monthrange(2014,startMonth)[1]
   lastDayEndMonth   = calendar.monthrange(2014,endMonth)[1]
   startDay    = int(lrand.randint(1,lastDayStartMonth))
   endDay      = int(lrand.randint(1,lastDayEndMonth))
   startHour   = int(lrand.randint(0,23))
   endHour     = int(lrand.randint(0,23))
   startMin    = int(lrand.randint(0,59))
   endMin      = int(lrand.randint(0,59))
   SDT=DT(2014,startMonth,startDay,startHour,startMin,0)
   EDT=DT(2014,endMonth  ,endDay  ,endHour  ,endMin, 59)
   repKey = "random" + str(i).zfill(3)
   results = genEvents(SDT,EDT,repKey,varKey,ips)
   records += results




###
###   sort the records (so excel et al don't have to...)
###
records.sort()
###
###   header comes after the sort function, else the 
###   header ends up at the bottom
###
records.insert(0,'recordKey|AB_Count|ISO_Time|dataKey')
for rec in records:
   print rec


